import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse } from "axios";
import { ElMessage, ElMessageBox } from "element-plus";
import { ResultData } from "@/interface/common";
import { isType, paramsDeal } from "@/utils/index";
import { showFullScreenLoading, tryHideFullScreenLoading } from "@/utils/handle";

export interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
  loading?: boolean;
  serverName?: string;
}

interface CusBlob {
  data: BlobPart;
  fileName: string;
}

const config = {
  baseURL: APP_CONFIG.baseServer,
  timeout: 600000,
};

//请求地址服务地址
export const getUrl = (serverName?: string) => {
  if (serverName) {
    return serverName;
  } else {
    return config.baseURL;
  }
};
//获取菜单id
export function getUrlMenu() {
  const url = window.location.href;
  const tempArr = url.split("?");
  let menuid = "";
  if (tempArr.length > 1) {
    const hashParams = new URLSearchParams(tempArr[1]);
    menuid = hashParams.get("menuid") || "";
  }
  //console.log(menuid);
  return menuid;
}

class RequestHttp {
  service: AxiosInstance;
  public constructor(config: AxiosRequestConfig) {
    // instantiation
    this.service = axios.create(config);

    /**
     * @description 请求拦截器
     * 客户端发送请求 -> [请求拦截器] -> 服务器
     * token校验(JWT) : 接受服务器返回的 token,存储到 vuex/pinia/本地储存当中
     */
    this.service.interceptors.request.use(
      (config: CustomAxiosRequestConfig) => {
        console.log(config, "config");
        config.loading ??= true;
        config.loading && showFullScreenLoading();

        config.baseURL = getUrl(config.serverName);
        const menuid = getUrlMenu();
        if (menuid) {
          if (!config.params) {
            config.params = {};
          }
          config.params["menuid"] = menuid;
        }
        if (APP_CONFIG.userInfo) {
          config.headers.set("userInfo", APP_CONFIG.userInfo);
        }
        config.headers.set("authorization", APP_CONFIG.token);
        return config;
      },
      (error: AxiosError) => {
        return Promise.reject(error);
      },
    );

    /**
     * @description 响应拦截器
     *  服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
     */
    this.service.interceptors.response.use(
      (response: AxiosResponse & { config: CustomAxiosRequestConfig }) => {
        const { data, config } = response;
        // console.log(data, response, "请求");
        config.loading && tryHideFullScreenLoading();

        //导出没有status_code，直接返回
        if (!data.status_code) {
          if (config.responseType == "blob") {
            let cType = response.headers["content-type"];
            //异常
            if (cType == "application/json") {
              ElMessage.warning(`导出失败~`);
              return Promise.reject(data);
            }
            let dis = response.headers["content-disposition"];
            if (dis) {
              const fileNameEncode = dis.split("filename=")[1].split(";")[0];
              const fileName = decodeURI(fileNameEncode);
              return {
                data,
                fileName,
              };
            }
            return data;
          }
          if (data && isType(data) == "string" && data.startsWith("<!DOCTYPE html>")) {
            ElMessage.warning(`登录已过期，请重新登录~`);
            return;
          }
          return data;
        }
        if (data.status_code === "0000" || data.status_code === "200" || data.success === true) {
          return data;
        } else {
          if (data.reason) {
            let msg = `提示 <span class="msg-desc">${data.reason}</span>`;
            ElMessageBox.alert(msg, "", {
              confirmButtonText: "确定",
              type: "warning",
              dangerouslyUseHTMLString: true,
            });
          }
          return Promise.reject(data);
        }
      },
      async (error: AxiosError) => {
        tryHideFullScreenLoading();
        //异常状态提示
        if (error.response && error.response.status) {
          const { status } = error.response;
          let message = "";
          switch (status) {
            case 400:
              message = "请求错误";
              break;
            case 401:
              message = "请求错误";
              break;
            case 404:
              message = "请求地址出错";
              break;
            case 405:
              message = "请求地址出错";
              break;
            case 408:
              message = "请求超时";
              break;
            case 500:
              message = "服务器内部错误!";
              break;
            case 501:
              message = "服务未实现!";
              break;
            case 502:
              message = "网关错误!";
              break;
            case 503:
              message = "服务不可用!";
              break;
            case 504:
              message = "网关超时!";
              break;
            case 505:
              message = "HTTP版本不受支持";
              break;
            default:
              message = "请求失败";
          }
          ElMessage.error(`${message}`);
        } else {
          ElMessage.error(`${error}`);
        }
        return Promise.reject(error);
      },
    );
  }

  /**
   * @description 常用请求方法封装
   */
  get<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
    params = paramsDeal(params);
    return this.service.get(url, { params, ..._object });
  }
  post<T>(url: string, params?: object | string, _object = {}): Promise<ResultData<T>> {
    params = paramsDeal(params);
    return this.service.post(url, params, _object);
  }
  put<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
    return this.service.put(url, params, _object);
  }
  delete<T>(url: string, params?: any, _object = {}): Promise<ResultData<T>> {
    return this.service.delete(url, { params, ..._object });
  }
  download(url: string, params?: object, _object = {}): Promise<BlobPart> {
    params = paramsDeal(params);
    return this.service.post(url, params, { ..._object, responseType: "blob" });
  }
  downloadGet(url: string, params?: object, _object = {}): Promise<CusBlob> {
    params = paramsDeal(params);
    return this.service.get(url, { params, ..._object, responseType: "blob" });
  }
  getJson<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
    return this.service.get(url, { params, ..._object });
  }

  // 无用户校验，不通用
  // downloadUrl(url: string, params?: object, serverName?: string) {
  //   url = urlJoint(url, params);
  //   return getUrl(serverName) + url;
  // }
}

export default new RequestHttp(config);
